package mp

import (
	"duoke/context"
	"duoke/internal/dao"
	"duoke/internal/model/entity"
	"duoke/model"
	"duoke/service"
	"duoke/utils/gconv"
	"duoke/utils/gjwt"
	"duoke/utils/orm"
	"duoke/utils/request"
	"duoke/utils/response"
	"duoke/utils/valid"
	"duoke/utils/yaml"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/util/grand"
)

var User = new(userCtl)

type userCtl struct{}

// 登录小程序
func (ctl *userCtl) Login(c *gin.Context) {
	req := request.JsonMap(c)
	if gconv.String(req["code"]) == "" {
		response.Error(c, "code缺失", nil)
		return
	}
	miniApp, err := service.Miniprogram.App(c)
	if err != nil {
		response.Error(c, err.Error(), nil)
		return
	}
	session, err := miniApp.Auth.Session(c, gconv.String(req["code"]))
	if err != nil {
		response.Error(c, err.Error(), nil)
		return
	}
	if session.OpenID == "" {
		response.Error(c, "异常错误，openid缺失", nil)
		return
	}
	user, err := service.User.Login(c, session.OpenID, session.SessionKey, session.UnionID)
	if err != nil {
		response.Error(c, err.Error(), nil)
		return
	}
	config := yaml.GetConfig()
	// 生成token
	token, err := gjwt.Build(gjwt.Data{Uid: user.Id, Url: config.Request.Domain}, 3600*24*365)
	if err != nil {
		response.Error(c, err.Error(), nil)
		return
	}
	response.Success(c, "登录成功", gin.H{"token": token})
}

// 更新昵称头像姓名手机号
func (ctl *userCtl) UpdateInfo(c *gin.Context) {
	var req model.ReqUser
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, valid.GetError(err.(validator.ValidationErrors), req), nil)
		return
	}
	// 更新用户主表
	err := service.User.UpdateInfo(c, req)
	if err != nil {
		response.Error(c, err.Error(), nil)
		return
	}
	// 更新商品表
	err = service.GoodsUser.UpdateInfo(c, req)
	if err != nil {
		response.Error(c, err.Error(), nil)
		return
	}
	response.Success(c, "保存成功", nil)
}

// 更新手机号
func (ctl *userCtl) UpdatePhone(c *gin.Context) {
	req := request.JsonMap(c)
	if gconv.String(req["code"]) == "" {
		response.Error(c, "code缺失", nil)
		return
	}
	goods, _ := service.Request.Goods(c)
	user, _ := service.Request.User(c)
	miniApp, err := service.Miniprogram.App(c)
	if err != nil {
		response.Error(c, err.Error(), nil)
		return
	}
	result, err := miniApp.PhoneNumber.GetUserPhoneNumber(c, gconv.String(req["code"]))
	if err != nil {
		return
	}
	if result.ErrCode != 0 {
		response.Error(c, result.ErrMsg, nil)
		return
	}
	err = service.User.UpdatePhone(c, result.PhoneInfo.PhoneNumber)
	if err != nil {
		response.Error(c, err.Error(), nil)
		return
	}
	// 更新商品表
	goodsUser := new(model.ReqGoodsUser)
	goodsUser.Phone = result.PhoneInfo.PhoneNumber
	_, err = orm.Db.Where("goods_id =? AND user_id = ?", goods.Id, user.Id).Update(goodsUser)
	if err != nil {
		response.Error(c, err.Error(), nil)
		return
	}
	response.Success(c, "保存成功", gin.H{"phone": result.PhoneInfo.PhoneNumber})
}

// 用户信息
func (ctl *userCtl) Info(c *gin.Context) {
	userR, _ := service.Request.User(c)
	req := request.JsonMap(c)
	if gconv.Int(req["goodsId"]) != 0 {
		user, err := service.GoodsUser.GetByGoodsUserId(c, gconv.Int(req["goodsId"]), userR.Id, "user_id,nickname,avatar,name,phone")
		if err == nil {
			user.Id = userR.Id
			response.Success(c, "", gin.H{
				"id":       user.Id,
				"nickname": user.Nickname,
				"avatar":   user.Avatar,
				"phone":    user.Phone,
			})
			return
		}
	}
	user, err := service.User.Info(c, "id,nickname,avatar,name,phone,money,user_money,score,sub_mch_id")
	if err != nil {
		response.Error(c, err.Error(), nil)
		return
	}
	response.Success(c, "", gin.H{
		"id":                            user.Id,
		"nickname":                      user.Nickname,
		"avatar":                        user.Avatar,
		"phone":                         user.Phone,
		"money":                         user.Money,
		"user_money":                    user.UserMoney,
		"score":                         user.Score,
		"sub_mch_id":                    user.SubMchId,
		"receive_score_qrcode":          context.Global.Domain + "/mp/qrcode?type=score_receive&id=" + gconv.String(user.Id),
		"receive_user_money_qrcode":     context.Global.Domain + "/mp/qrcode?type=user_money_receive&id=" + gconv.String(user.Id),
		"receive_merchant_money_qrcode": context.Global.Domain + "/mp/qrcode?type=merchant_money_receive&id=" + gconv.String(user.Id),
	})
}

// 用户订单
func (ctl *userCtl) Order(c *gin.Context) {
	userR, _ := service.Request.User(c)
	where := "user_id = " + gconv.String(userR.Id)
	where += " AND pay_state = 1"
	query := orm.Db.Desc("id").
		Cols("id,goods_id,goods_title,goods_photo,pay_amount,order_no,pay_time,phone,address,tracking_number," +
			"tracking_state,tracking_company").
		Where(where)
	order := make([]model.Order, 0)
	err := query.Find(&order)
	if err != nil {
		response.Error(c, err.Error(), nil)
		return
	}
	response.Success(c, "success", order)
}

// 用户充值
func (ctl *userCtl) Recharge(c *gin.Context) {
	req := request.JsonMap(c)
	orderNo := gconv.String(req["orderNo"])
	if orderNo == "" {
		response.Error(c, "订单号缺失", nil)
		return
	}
	var order *entity.UserMoneyLog
	err := dao.UserMoneyLog.Ctx(c).Where("order_no", orderNo).Where("status", 0).Scan(&order)
	if err != nil || order == nil {
		response.Error(c, "订单不存在", nil)
		return
	}
	user, err := dao.User.Ctx(c).Where("id", order.UserId).One()
	if err != nil || user.IsEmpty() {
		response.Error(c, "用户不存在", nil)
		return
	}
	SubMchId := gconv.String(user.Map()["sub_mch_id"])
	config := yaml.GetConfig()
	if config.SubMch.SubType == "2" {
		SubMchId = gconv.String(user.Map()["sub_mch_id"])
	}
	// 获取支付参数
	notifyUrl := context.Global.Domain + "/mp/notify/user_recharge_pay"
	payConf, err := service.WechatPay.OrderV2(c, notifyUrl, gconv.String(user.Map()["openid"]), order.OrderNo, float32(order.Amount), "user recharge",
		SubMchId)
	if err != nil {
		response.Error(c, err.Error(), nil)
		return
	}
	response.Success(c, "success", gin.H{
		"pay":   payConf,
		"order": order,
	})
}

// 用户提现
func (ctl *userCtl) Cash(c *gin.Context) {
	req := request.JsonMap(c)
	userR, _ := service.Request.User(c)
	// 用户
	var user *entity.User
	err := dao.User.Ctx(c).Where("id", userR.Id).Scan(&user)
	if err != nil || user.Id == 0 {
		response.Error(c, "用户不存在", nil)
		return
	}
	if user.UserMoney <= 0 {
		response.Error(c, "佣金账户余额不足", nil)
		return
	}
	if gconv.Float64(req["amount"]) > user.UserMoney {
		response.Error(c, "可提现最大金额："+gconv.String(user.UserMoney)+"元", nil)
		return
	}
	if gconv.Float64(req["amount"]) > 500 {
		response.Error(c, "单笔最大可提现500元", nil)
		return
	}
	err = service.User.UserMoney(c, user.Id, -gconv.Float64(req["amount"]), "小程序提现", "user_cash")
	if err != nil {
		response.Error(c, err.Error(), nil)
		return
	}
	// 计算提现手续费
	otherSetting, err := service.AccountSetting.Info(c, "other")
	if err != nil {
		response.Error(c, err.Error(), nil)
		return
	}
	cash_fee := gconv.Float64(req["amount"]) * gconv.Float64(otherSetting["cash_fee_rate"])
	sendAmount := gconv.Float64(req["amount"]) - cash_fee
	// 商转零发放
	orderNo := gtime.Now().Format("YmdHis") + "cash" + gconv.String(grand.N(0, 99))
	isSuccess, err := service.WechatPay.TransferV3(c, user.Openid, sendAmount, orderNo, "佣金提现，手续费："+gconv.String(cash_fee))
	if err != nil {
		service.User.UserMoney(c, user.Id, gconv.Float64(req["amount"]), "提现失败，退回金额", "user_cash_fail")
		response.Error(c, err.Error(), nil)
		return
	}
	if isSuccess {
		response.Success(c, "零钱发放成功", nil)
		return
	} else {
		service.User.UserMoney(c, user.Id, gconv.Float64(req["amount"]), "提现失败，退回金额", "user_cash_fail")
		response.Error(c, "零钱发放失败", nil)
		return
	}
}

// Save 修改用户数据
func (ctl *userCtl) Save(c *gin.Context) {
	var req model.ReqUser
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, err.Error(), nil)
		return
	}
	err := service.User.SaveV2(c, &req)
	if err != nil {
		response.Error(c, err.Error(), nil)
		return
	}
	response.Success(c, "保存成功", nil)
}
func (ctl *userCtl) RankingVersion(c *gin.Context) {
	var req model.ReqListV2
	if err := c.ShouldBind(&req); err != nil {
		response.Error(c, err.Error(), nil)
		return
	}
	list, total, err := service.Group.RankingVersion(c, &req)
	if err != nil {
		response.Error(c, err.Error(), nil)
		return
	}
	response.Success(c, "success", gin.H{"total": total, "list": list})
}

// Withdrawal 小程序用户体现需要后台审核
func (ctl *userCtl) Withdrawal(c *gin.Context) {
	var req model.ReqWithdrawal
	if err := c.ShouldBind(&req); err != nil {
		response.Error(c, valid.GetError(err.(validator.ValidationErrors), req), nil)
		return
	}
	err := service.Group.Withdrawal(c, &req)
	if err != nil {
		response.Error(c, err.Error(), nil)
		return
	}
	response.Success(c, "success", nil)
}
